package com.github.cakin.shiro.chapter19.web.bind.method;

import com.github.cakin.shiro.chapter19.web.bind.annotation.CurrentUser;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

/**
 * @className: CurrentUserMethodArgumentResolver
 * @description: 注解参数解析
 * @date: 2020/5/26
 * @author: cakin
 */
public class CurrentUserMethodArgumentResolver implements HandlerMethodArgumentResolver {

    public CurrentUserMethodArgumentResolver() {
    }

    public boolean supportsParameter(MethodParameter parameter) {
        if (parameter.hasParameterAnnotation(CurrentUser.class)) {
            return true;
        }
        return false;
    }

    /**
     * 功能描述：注解参数解析器，获得当前用户数据
     *
     * @author cakin
     * @date 2020/5/26
     * @param parameter 注解所在方法
     * @param mavContainer 模型视图容器
     * @param webRequest web请求，里面带有用户信息
     * @param binderFactory web数据绑定工厂
     * @return Object 用户对象
     * @throws Exception 异常
     * @description: 调用栈如下：
     * resolveArgument:31, CurrentUserMethodArgumentResolver (com.github.cakin.shiro.chapter16.web.bind.method)
     * resolveArgument:79, HandlerMethodArgumentResolverComposite (org.springframework.web.method.support)
     * getMethodArgumentValues:157, InvocableHandlerMethod (org.springframework.web.method.support)
     * invokeForRequest:124, InvocableHandlerMethod (org.springframework.web.method.support)
     * invokeAndHandle:104, ServletInvocableHandlerMethod (org.springframework.web.servlet.mvc.method.annotation)
     * invokeHandleMethod:748, RequestMappingHandlerAdapter (org.springframework.web.servlet.mvc.method.annotation)
     * handleInternal:689, RequestMappingHandlerAdapter (org.springframework.web.servlet.mvc.method.annotation)
     * handle:83, AbstractHandlerMethodAdapter (org.springframework.web.servlet.mvc.method)
     * doDispatch:945, DispatcherServlet (org.springframework.web.servlet)
     * doService:876, DispatcherServlet (org.springframework.web.servlet)
     * processRequest:931, FrameworkServlet (org.springframework.web.servlet)
     * doGet:822, FrameworkServlet (org.springframework.web.servlet)
     * service:735, HttpServlet (javax.servlet.http)
     * service:807, FrameworkServlet (org.springframework.web.servlet)
     * service:848, HttpServlet (javax.servlet.http)
     * handle:669, ServletHolder (org.eclipse.jetty.servlet)
     * doFilter:1336, ServletHandler$CachedChain (org.eclipse.jetty.servlet)
     * doFilter:61, ProxiedFilterChain (org.apache.shiro.web.servlet)
     * executeChain:108, AdviceFilter (org.apache.shiro.web.servlet)
     * doFilterInternal:137, AdviceFilter (org.apache.shiro.web.servlet)
     * doFilter:125, OncePerRequestFilter (org.apache.shiro.web.servlet)
     * doFilter:66, ProxiedFilterChain (org.apache.shiro.web.servlet)
     * executeChain:108, AdviceFilter (org.apache.shiro.web.servlet)
     * doFilterInternal:137, AdviceFilter (org.apache.shiro.web.servlet)
     * doFilter:125, OncePerRequestFilter (org.apache.shiro.web.servlet)
     * doFilter:66, ProxiedFilterChain (org.apache.shiro.web.servlet)
     * executeChain:449, AbstractShiroFilter (org.apache.shiro.web.servlet)
     * call:365, AbstractShiroFilter$1 (org.apache.shiro.web.servlet)
     * doCall:90, SubjectCallable (org.apache.shiro.subject.support)
     * call:83, SubjectCallable (org.apache.shiro.subject.support)
     * execute:383, DelegatingSubject (org.apache.shiro.subject.support)
     * doFilterInternal:362, AbstractShiroFilter (org.apache.shiro.web.servlet)
     * doFilter:125, OncePerRequestFilter (org.apache.shiro.web.servlet)
     * invokeDelegate:344, DelegatingFilterProxy (org.springframework.web.filter)
     * doFilter:261, DelegatingFilterProxy (org.springframework.web.filter)
     * doFilter:1307, ServletHandler$CachedChain (org.eclipse.jetty.servlet)
     * doFilterInternal:88, CharacterEncodingFilter (org.springframework.web.filter)
     * doFilter:108, OncePerRequestFilter (org.springframework.web.filter)
     * doFilter:1307, ServletHandler$CachedChain (org.eclipse.jetty.servlet)
     * doHandle:453, ServletHandler (org.eclipse.jetty.servlet)
     * handle:137, ScopedHandler (org.eclipse.jetty.server.handler)
     * handle:560, SecurityHandler (org.eclipse.jetty.security)
     * doHandle:231, SessionHandler (org.eclipse.jetty.server.session)
     * doHandle:1072, ContextHandler (org.eclipse.jetty.server.handler)
     * doScope:382, ServletHandler (org.eclipse.jetty.servlet)
     * doScope:193, SessionHandler (org.eclipse.jetty.server.session)
     * doScope:1006, ContextHandler (org.eclipse.jetty.server.handler)
     * handle:135, ScopedHandler (org.eclipse.jetty.server.handler)
     * handle:255, ContextHandlerCollection (org.eclipse.jetty.server.handler)
     * handle:154, HandlerCollection (org.eclipse.jetty.server.handler)
     * handle:116, HandlerWrapper (org.eclipse.jetty.server.handler)
     * handle:365, Server (org.eclipse.jetty.server)
     * handleRequest:485, AbstractHttpConnection (org.eclipse.jetty.server)
     * headerComplete:926, AbstractHttpConnection (org.eclipse.jetty.server)
     * headerComplete:988, AbstractHttpConnection$RequestHandler (org.eclipse.jetty.server)
     * parseNext:635, HttpParser (org.eclipse.jetty.http)
     * parseAvailable:235, HttpParser (org.eclipse.jetty.http)
     * handle:82, AsyncHttpConnection (org.eclipse.jetty.server)
     * handle:628, SelectChannelEndPoint (org.eclipse.jetty.io.nio)
     * run:52, SelectChannelEndPoint$1 (org.eclipse.jetty.io.nio)
     * runJob:608, QueuedThreadPool (org.eclipse.jetty.util.thread)
     * run:543, QueuedThreadPool$3 (org.eclipse.jetty.util.thread)
     * run:748, Thread (java.lang)
     */
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) throws Exception {
        CurrentUser currentUserAnnotation = parameter.getParameterAnnotation(CurrentUser.class);
        Object attribute = webRequest.getAttribute(currentUserAnnotation.value(), NativeWebRequest.SCOPE_REQUEST);
        // User{id=1, organizationId=1, username='admin', password='d3c59d25033dbf980d29554025c23a75',
        // salt='8d78869f470951332959580424d4bf4f', roleIds=[1], locked=false}
        return attribute;
    }
}
